﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace WeForms.Controls
{
    /// <summary>
    /// Represents a skinned button control, optimized for the 
    /// usage in touch interfaces.
    /// </summary>
    public class TouchButton : Control
    {
        private TouchButtonColor _colorScheme;
        /// <summary>
        /// Gets or sets the color scheme of this button. 
        /// </summary>
        /// <value>The color scheme.</value>
        public TouchButtonColor ColorScheme
        {
            get { return _colorScheme; }
            set
            {
                if (_colorScheme == value) return;
                _colorScheme = value;
                Invalidate();
            }
        }

        private bool _hovered;
        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="TouchButton"/> is hovered.
        /// </summary>
        /// <value><c>true</c> if hovered; otherwise, <c>false</c>.</value>
        internal bool Hovered
        {
            get { return _hovered; }
            private set
            {
                if (_hovered == value) return;
                _hovered = value;
                Invalidate();
            }
        }

        private bool _pressed;
        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="TouchButton"/> is pressed.
        /// </summary>
        /// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
        internal bool Pressed
        {
            get { return _pressed; }
            private set
            {
                if (_pressed == value) return;
                _pressed = value;
                Invalidate();
            }
        }

        private bool _checked;
        /// <summary>
        /// Gets or sets a value indicating whether this <see cref="TouchButton"/> is checked.
        /// </summary>
        /// <value><c>true</c> if checked; otherwise, <c>false</c>.</value>
        public bool Checked
        {
            get { return _checked; }
            set
            {
                if (_checked == value) return;
                _checked = value;
                Invalidate();
                OnCheckedChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to check or uncheck this button
        /// as it's clicked.
        /// </summary>
        /// <value><c>true</c> if check or uncheck this button on clicking; otherwise, <c>false</c>.</value>
        public bool CheckOnClick { get; set; }

        /// <summary>
        /// Gets or sets the text associated with this control.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// The text associated with this control.
        /// </returns>
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                if (base.Text == value) return;
                base.Text = value;
                Invalidate();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to use the internal 
        /// layout manager for determining the button size.
        /// </summary>
        /// <value></value>
        /// <returns>true if enabled; otherwise, false.
        /// </returns>
        [Browsable(true)]
        public override bool AutoSize
        {
            get
            {
                return base.AutoSize;
            }
            set
            {
                if (base.AutoSize == value) return;
                base.AutoSize = value;
                SetStyle(ControlStyles.FixedHeight, value);
                SetStyle(ControlStyles.FixedWidth, value);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TouchButton"/> class.
        /// </summary>
        public TouchButton()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.ContainerControl, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            base.Font = TouchButtonRenderer.DefaultFont;
            Padding = new Padding(13);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseDown"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            Pressed = true;
            base.OnMouseDown(e);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            Pressed = false;
            if (CheckOnClick)
            {
                Checked = !Checked;
            }
            base.OnMouseUp(e);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseEnter"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
        protected override void OnMouseEnter(EventArgs e)
        {
            Hovered = true;
            base.OnMouseEnter(e);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.MouseLeave"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
        protected override void OnMouseLeave(EventArgs e)
        {
            Hovered = false;
            base.OnMouseEnter(e);
        }

        /// <summary>
        /// Performs the work of setting the specified bounds of this control.
        /// </summary>
        /// <param name="x">The new <see cref="P:System.Windows.Forms.Control.Left"/> property value of the control.</param>
        /// <param name="y">The new <see cref="P:System.Windows.Forms.Control.Top"/> property value of the control.</param>
        /// <param name="width">The new <see cref="P:System.Windows.Forms.Control.Width"/> property value of the control.</param>
        /// <param name="height">The new <see cref="P:System.Windows.Forms.Control.Height"/> property value of the control.</param>
        /// <param name="specified">A bitwise combination of the <see cref="T:System.Windows.Forms.BoundsSpecified"/> values.</param>
        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            if (AutoSize)
            {
                Size preferredSize = PreferredSize;
                width = preferredSize.Width;
                height = preferredSize.Height;
            }
            base.SetBoundsCore(x, y, width, height, specified);
        }

        /// <summary>
        /// Retrieves the size of a rectangular area into which a control can be fitted.
        /// </summary>
        /// <param name="proposedSize">The custom-sized area for a control.</param>
        /// <returns>
        /// An ordered pair of type <see cref="T:System.Drawing.Size"/> representing the width and height of a rectangle.
        /// </returns>
        public override Size GetPreferredSize(Size proposedSize)
        {
            Size s = TextRenderer.MeasureText(Text, Font, proposedSize);
            s.Width += Padding.Horizontal;
            s.Height += Padding.Vertical;
            return s;
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            TouchButtonRenderer.DrawButton(this, e.Graphics, ClientRectangle);
        }

        /// <summary>
        /// Occurs when the value of <see cref="Checked"/> changed.
        /// </summary>
        public event EventHandler CheckedChanged;
        /// <summary>
        /// Raises the <see cref="CheckedChanged"/> event.
        /// </summary>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        protected virtual void OnCheckedChanged(EventArgs e)
        {
            if (CheckedChanged != null) CheckedChanged(this, e);
        }
    }
}
